﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#pragma once
#include "GmStructureFamily.h"
#include "FamilyParameterType.h"
#include "ParameterProcessType.h"
#include "GraphicsNodeReferenceType.h"

namespace gcmp
{
    class IDocument;
    class IInstance;
    class IPolyCurve;
    class UniIdentity;
    class ElementId;
    class IReferencePlane;
    class Coordinate3d;
    class Vector3d;
    class IParameterValueStorage;
    class GraphicsNodeId;
}

namespace gfam
{
    class IFamilyDistanceConstraint;
    class IFamilyDistanceRatioConstraint;
    class IFamilyGeometryConstraint;
    class IFamily2DSketchLine;
    class IFamilySketchPlane;
    class IFamilyManager;
    class IFamilySweep;
    class IFamilyPlaneSplitForm;
    class IFamilySketch2D;
    class IFamilySlopedExtrusion;
    class IFamilyMultiDistanceDimension;
    class IFamilyManager;
    class IFamilyParameterDefinition;
    class IFamilyAngleConstraint;
}

namespace FamilyTemplateConst
{
    const double CommonExtend = 400;
    const double CenterExtend = 500;
    const double CenterLength = 5000;
    const double CommonLength = 4000;
    const double DimScale = 500.0;
};


namespace gcmp
{
    // 创建和获取时的类型参数
    enum DefaultReferencePlanesOptions
    {
        NoneReferencePlane             = 0,
        LeftReferencePlane             = 1 << 0,
        RightReferencePlane            = 1 << 1,
        FrontReferencePlane            = 1 << 2,
        BackReferencePlane             = 1 << 3,
        TopReferencePlane              = 1 << 4,
        BottomReferencePlane           = 1 << 5,
        LeftRightCenterReferencePlane  = 1 << 6,
        FrontBackCenterReferencePlane  = 1 << 7,
        TopBottomCenterReferencePlane  = 1 << 8,
    };

    // 默认的几个参照平面，在一个族文档里不一定会所有的都创建
    class DefaultReferencePlanes
    {
    public:
        DefaultReferencePlanes() :m_pLeft(nullptr), m_pRight(nullptr)
            , m_pFront(nullptr), m_pBack(nullptr)
            , m_pTop(nullptr), m_pBottom(nullptr)
            , m_pLeftRightCenter(nullptr), m_pFrontBackCenter(nullptr), m_pTopBottomCenter(nullptr)
        {
        }

    public:
        gcmp::IReferencePlane *m_pLeft;
        gcmp::IReferencePlane *m_pRight;
        gcmp::IReferencePlane *m_pFront;
        gcmp::IReferencePlane *m_pBack;
        gcmp::IReferencePlane *m_pTop;
        gcmp::IReferencePlane *m_pBottom;
        gcmp::IReferencePlane *m_pLeftRightCenter;
        gcmp::IReferencePlane *m_pFrontBackCenter;
        gcmp::IReferencePlane *m_pTopBottomCenter;
    };

    // 初始创建的参照平面位置
    class ReferencePlaneOffsets
    {
    public:
        ReferencePlaneOffsets(double leftOffset = 200, double rightOffset = 200
            , double frontOffset = 100, double backOffset = 100
            , double topOffset = 3000, double bottomOffset = 3000)
            : m_leftOffset(leftOffset), m_rightOffset(rightOffset)
            , m_frontOffset(frontOffset), m_backOffset(backOffset)
            , m_topOffset(topOffset), m_bottomOffset(bottomOffset)
        {
        }

    public:
        double m_leftOffset;
        double m_rightOffset;
        double m_frontOffset;
        double m_backOffset;
        double m_topOffset;
        double m_bottomOffset;
    };

    class GM_STRUCTURE_FAMILY_EXPORT FamStructureTemplateUtility
    {
    public:
        //族管理中添加族参数
        static bool AddBuiltInParameterDefination(
                gcmp::IDocument* pDbDoc,
                gcmp::OwnerPtr<gcmp::IParameterValueStorage> upParamValue,
                const gcmp::UniIdentity& uid,
                bool bIsInstance,
                bool bIsDeterminedByFormula,
                const std::wstring& formula,
                gcmp::ParameterProcessType ppt,
                gfam::FamilyParameterType eParameterType
        );
        //族管理中添加族参数
        static bool FamStructureTemplateUtility::AddFamilyParameterDefination(gcmp::IDocument* pDbDoc,
            const std::wstring& name,
            gfam::FamilyParameterType parameterType,
            bool bIsInstance,
            const std::wstring& formula,
            const UniIdentity& unitTypeId,
            const UniIdentity& paramTypeId);

        //初始化线式族环境
        static void InitLineFamilyDocument(gcmp::IDocument* pDbDoc, bool bIsInPlaceEditMode = false);

        //初始化轮廓族的环境
        static void InitFamilyBasedOnProfileFamilyDocument(gcmp::IDocument* pDbDoc, bool bIsInPlaceEditMode = false);
        // 初始化墙族的环境
        static void InitWallFamilyDocument(gcmp::IDocument* pDbDoc, bool isVariableSectionWall = false);
        //初始化墙族的环境
        static void InitWallFamilyDocument2(gcmp::IDocument* pDbDoc, bool bIsInPlaceEditMode = false, bool isVariableSectionWall = false);
        //初始化窗族的环境
        static void InitWindowFamilyDocument(gcmp::IDocument* pDbDoc, bool bIsInPlaceEditMode = false);
        //初始化门族的环境
        static void InitDoorFamilyDocument(gcmp::IDocument* pDbDoc, bool bIsInPlaceEditMode = false);
        //初始化梁族的环境
        static void InitBeamFamilyDocument(gcmp::IDocument* pDbDoc, bool bIsInPlaceEditMode = false);
        // 初始化矩形柱的族环境
        static void InitRectangleColumnFamilyDocument(gcmp::IDocument* pDbDoc);
        static void InitCircleColumnFamilyDocument(gcmp::IDocument* pDbDoc);
        //初始化轮廓族的环境
        static void InitProfileFamilyDocument(gcmp::IDocument* pDbDoc, bool bIsInPlaceEditMode = false);
        //创建内置的墙体，项目中使用
        static void CreateBuiltInWallBody(gcmp::IDocument* pDbDoc, const gcmp::UniIdentity thicknessParamUid, bool isVariableSectionWall = false);
        // 自定义截面柱族
        static bool InitCustomizedProfileColumnFamilyDocument(gcmp::IDocument* pDbDoc);
        static bool CreateCustomizedProfileColumnBody(IDocument* pDoc, const IPolyCurve* pLoop);
        // 矩形梁族
        static bool InitRectBeamFamilyDocument(IDocument* pDoc);
        static bool AddRectBeamType(gfam::IFamilyManager* pFamilyManager, const std::wstring& familyType, double profileWidth, double profileHeight);
        static bool CreateRectBeamBody(IDocument* pDoc);
        // 变截面矩形梁族
        static bool InitVariableSectionRectBeamFamilyDocument(IDocument* pDoc);
        static bool AddVariableSectionRectBeamType(gfam::IFamilyManager* pFamilyManager, const std::wstring& familyType, double profileStartHeight, double profileEndHeight, double profileWidth);
        static bool CreateVariableSectionRectBeamBody(IDocument* pDoc);
        // 自定义截面梁族
        static bool InitCustomizedProfileBeamFamilyDocument(IDocument* pDoc);
        static bool CreateCustomizedProfileBeamBody(IDocument* pDbDoc, const IPolyCurve* pLoop);

        // 板族
        static bool InitFloorFamilyDocument(IDocument* pDoc);
        static bool AddFloorType(gfam::IFamilyManager* pFamilyManager, const std::wstring& familyType, double thickness);
        static bool CreateFloorBody(IDocument* pDoc);

        // 板洞族
        static bool InitPlateHoleFamilyDocument(IDocument* pDoc);
        static bool CreatePlateHoleBody(IDocument* pDoc);

        // 筏板基础 族
        static bool InitRaftFoundationFamilyDocument(IDocument* pDoc);
        static bool AddRaftFoundationType(gfam::IFamilyManager* pFamilyManager, const std::wstring& familyType, double thickness);
        static bool CreateRaftFoundationBody(IDocument* pDoc);

        // 屋顶族
        static bool InitRoofFamilyDocument(IDocument* pDoc);
        static bool AddRoofType(gfam::IFamilyManager* pFamilyManager, const std::wstring& familyType, double thickness);
        static bool CreateRoofBody(IDocument* pDoc);

        // 初始化墙洞族的环境
        static bool InitRectWallHoleFamilyDocument(gcmp::IDocument* pDbDoc);
        static bool AddRectWallHoleType(gfam::IFamilyManager* pFamilyManager, const std::wstring& familyType, double profileWidth, double profileHeight);
        static bool CreateRectWallHoleBody(IDocument* pDoc);

        // 条形基础的相关操作
        // 初始化矩形截面条形基础族的环境
        static bool InitRectStripFoundationFamilyDocument(gcmp::IDocument* pDbDoc);
        // 添加矩形截面条形基础族类型
        static bool AddRectStripFoundationType(gfam::IFamilyManager* pFamilyManager, const std::wstring& familyType, double profileWidth, double profileHeight);
        // 代码创建矩形截面条形基础族
        static bool CreateRectStripFoundationBody(gcmp::IDocument* pDbDoc);
        // 初始化T形截面条形基础族的环境
        static bool InitTStripFoundationFamilyDocument(gcmp::IDocument* pDbDoc);
        // 添加T形截面条形基础族类型
        static bool AddTStripFoundationType(gfam::IFamilyManager* pFamilyManager, const std::wstring& familyType, double b, double b1, double b2, double h1, double h2, double h3);
        // 代码创建T形截面条形基础族
        static bool CreateTStripFoundationBody(gcmp::IDocument* pDbDoc);

    public:
        static void CreateSweepBody(gcmp::IDocument* pDbDoc, bool isVariableSection);
        static bool AddVariableSectionWallParameters(gcmp::IDocument* pDbDoc, gfam::IFamilyManager* pFamilyManager);
        static gfam::IFamilyPlaneSplitForm *CutVariableSectionBody(gcmp::IDocument* pDbDoc, gfam::IFamilySweep* pSweepBody
            , IReferencePlane *pRefLinePlane, IReferencePlane *pBottomPlane, IReferencePlane *pLeftPlane, IReferencePlane *pRightPlane);
        static gfam::IFamilyPlaneSplitForm *CutVariableSectionBody(gcmp::IDocument* pDbDoc, ElementId bodyElementId
            , IReferencePlane *pRefLinePlane, IReferencePlane *pBottomPlane, IReferencePlane *pLeftPlane, IReferencePlane *pRightPlane
            , const std::wstring &startHeightParam, const std::wstring &endHeightParam, bool keepReverse);

        static void CreateRectangleColumnBody(gcmp::IDocument* pDbDoc);
        static void CreateCircleColumnBody(gcmp::IDocument* pDbDoc);

    public:
        // 创建族文档常用的参照平面，refPlaneOptions指定需要创建哪些
        static bool CreateDefaultReferencePlanes(gcmp::IDocument* pDbDoc
            , DefaultReferencePlanesOptions refPlaneOptions, const ReferencePlaneOffsets &refPlaneOffsets
            , DefaultReferencePlanes &refPlanes);

        // 获取族文档常用的参照平面，refPlaneOptions指定需要获取哪些
        static bool GetDefaultReferencePlanes(gcmp::IDocument* pDbDoc, DefaultReferencePlanesOptions refPlaneOptions, DefaultReferencePlanes &refPlanes);

        // 创建参照平面之间的距离约束
        static gfam::IFamilyDistanceConstraint* CreateDistanceConstraint(gcmp::IDocument* pDbDoc
            , IReferencePlane *pFirstRefPlane, IReferencePlane *pSecondRefPlane
            , const Coordinate3d &coord, const Vector3d &dimPosition);
        // 创建草图线之间的距离约束
        static gfam::IFamilyDistanceConstraint* CreateDistanceConstraint(gcmp::IDocument* pDbDoc
            , const gfam::IFamily2DSketchLine *pFirstLine, const gfam::IFamily2DSketchLine *pSecondLine
            , const gfam::IFamilySketchPlane* pSketchPlane, const Vector3d &dimPosition);

        // 创建参照平面之间的等距约束
        static gfam::IFamilyDistanceRatioConstraint *CreateEqualConstraint(gcmp::IDocument* pDbDoc
            , IReferencePlane *pFirstRefPlane, IReferencePlane *pSecondRefPlane, IReferencePlane *pMidRefPlane
            , const Coordinate3d &coord, const Vector3d &dimPosition);
        // 创建草图线之间的额等距约束
        static gfam::IFamilyDistanceRatioConstraint *CreateEqualConstraint(gcmp::IDocument* pDbDoc
            , gfam::IFamily2DSketchLine *pFirstLine, gfam::IFamily2DSketchLine *pSecondLine, gfam::IFamily2DSketchLine *pMidLine
            , gfam::IFamilySketchPlane* pSketchPlane, const Vector3d &dimPosition);
        // 创建草图线和参考平面之间的等距约束
        static gfam::IFamilyDistanceRatioConstraint *CreateEqualConstraint(gcmp::IDocument* pDbDoc
            , const gfam::IFamily2DSketchLine *pFirstLine, const gfam::IFamily2DSketchLine *pSecondLine, const IReferencePlane *pMidRefPlane
            , const gfam::IFamilySketchPlane* pSketchPlane, const Vector3d &dimPosition);

        // 创建草图线与参照平面的对齐约束
        static gfam::IFamilyGeometryConstraint *CreateAlignConstraint(gcmp::IDocument* pDbDoc
            , IReferencePlane *pRefPlane, gfam::IFamily2DSketchLine *pSketchLine, gfam::IFamilySketchPlane* pSketchPlane);

        // 创建草图线两个端点与参照平面的对齐约束
        static bool CreateStartEndPtAlignConstraints(gcmp::IDocument* pDbDoc
            , IReferencePlane *pStartRefPlane, IReferencePlane *pEndRefPlane
            , gfam::IFamily2DSketchLine *pSketchLine, gfam::IFamilySketchPlane* pSketchPlane);

        //创建一个矩形并加入到草图中
        // //vts：矩形的四个顶点，0-1是底边
        //pFamLine：获得的矩形的四条边，0是底边线
        static void CreateAndAddRectangle(gcmp::IDocument* pDoc, 
            const gfam::IFamilySketchPlane* pSketchPlane, 
            const gfam::IFamilySketch2D* pSketch, 
            const gcmp::Vector3d vts[4], 
            gfam::IFamily2DSketchLine* pFamLine[4]);

        static gfam::IFamilyDistanceConstraint* CreateDistanceConstraint(
            gcmp::IDocument* pDoc
            , const gcmp::Vector3d& dimPos
            , double                    dimScale
            , const gcmp::Coordinate3d& coord
            , const gcmp::ElementId& refId1
            , gcmp::GraphicsNodeReferenceType  refType1
            , const gcmp::GraphicsNodeId& leafTag1
            , const gcmp::ElementId& refId2
            , gcmp::GraphicsNodeReferenceType  refType2
            , const gcmp::GraphicsNodeId& leafTag2
            , gfam::IFamilyMultiDistanceDimension*& pDimBind
        );

        static gfam::IFamilyAngleConstraint* CreateAngleConstraint(
            gcmp::IDocument* pDoc
            , const gcmp::Coordinate3d& coord
            , gcmp::IElement* pEle1
            , gcmp::GraphicsNodeReferenceType  refType1
            , const gcmp::GraphicsNodeId& leafTag1
            , gcmp::IElement* pEle2
            , gcmp::GraphicsNodeReferenceType  refType2
            , const gcmp::GraphicsNodeId& leafTag2
        );

        //草图外用的
        //返回值可能为nullptr
        static gfam::IFamilyGeometryConstraint* CreateEqualConstraint(
            IDocument* pDoc
            , const gcmp::Coordinate3d& coord
            , IElement* pEle1
            , gcmp::GraphicsNodeReferenceType  refType1
            , const gcmp::GraphicsNodeId& leafTag1
            , IElement* pEle2
            , gcmp::GraphicsNodeReferenceType  refType2
            , const gcmp::GraphicsNodeId& leafTag2
        );

    private:
        static gfam::IFamilySketch2D* CreateRectBeamProfileSketch(IDocument* pDoc);
        static gfam::IFamilySketch2D* CreateRectBeamPathSketch(IDocument* pDoc);

        static gfam::IFamilySketch2D* CreateVariableSectionRectBeamProfileSketch(IDocument* pDoc, const UniIdentity& widthParamUid, const UniIdentity& heightParamUid);
        static gfam::IFamilySketch2D* CreateVariableSectionRectBeamPathSketch(IDocument* pDoc);

        static gfam::IFamilySketch2D* CreateCustomizedProfileBeamProfileSketch(IDocument* pDoc, const IPolyCurve* pLoop);
        static gfam::IFamilySketch2D* CreateCustomizedProfileBeamPathSketch(IDocument* pDoc);
        // 创建异形柱体的轮廓，返回轮廓所在的草图
        static gfam::IFamilySketch2D* CreateCustomizedProfileColumnProfileSketch(gcmp::IDocument* pDbDoc, const gcmp::IPolyCurve* pLoop);
        // 使用斜拉伸体创建柱
        static gfam::IFamilySlopedExtrusion* CreateColumnBodyBySlopedExtrusion(gcmp::IDocument* pDbDoc, const gfam::IFamilySketch2D* pSectionSketch);
        // 创建自定义截面
        static gfam::IFamilySketch2D* CreateCustomizedProfile(IDocument* pDoc, const Coordinate3d& refCoord, const Coordinate3d& sketchCoord, const IPolyCurve* pLoop);

        // 创建条形基础的扫略路径，返回路径所在的草图
        static gfam::IFamilySketch2D* CreateStripFoundationPath(gcmp::IDocument* pDoc);
        // 创建条形基础的轮廓，返回轮廓所在的草图
        static gfam::IFamilySketch2D* CreateRectStripFoundationProfile(gcmp::IDocument* pDoc);
        static gfam::IFamilySketch2D* CreateModelInvertedTProfile(gcmp::IDocument* pDoc);
        static bool AddTStripFoundationFamilyReferencePlane(gcmp::IDocument * pDoc, gcmp::ElementId widthParamId);

        static gfam::IFamilyParameterDefinition* CreateParameterDefination(
            gcmp::IDocument* pDbDoc,
            const gcmp::UniIdentity& uid,
            bool bIsInstance,
            bool bIsDeterminedByFormula,
            const std::wstring& formula,
            gfam::FamilyParameterType eParameterType
        );

        static void AddWindowParameterDefination(gcmp::IDocument* pDbDoc, double dWall, double dSillH, double dHeight, double dWidth);
        static void AddDoorParameterDefination(gcmp::IDocument* pDbDoc, double wallThickness, double doorHeight, double doorWidth);

        static void SetFamParameterType(gcmp::IDocument* pDbDoc, const gcmp::UniIdentity& uid, gfam::FamilyParameterType fpt);

        static std::wstring CreateBuiltInProfileFamilyDocument(const std::wstring& familyName);
    };
}
